/*
#Copyright (c) 2013, Philippe Bordron <philippe.bordron@gmail.com>
#
# This file is part of SIPPER.
#
# DCC is free software: you can redistribute it and/or modify
# it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# DCC is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU LESSER GENERAL PUBLIC LICENSE for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# along with SIPPER.  If not, see <http://www.gnu.org/licenses/>
*/
package combi.wip.sipper.modeling.integratedModel;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;

import combi.sipper.modeling.distances.DistanceBetweenGenes;
import combi.wip.sipper.modeling.Protein;
import combi.wip.sipper.modeling.genomes.Gene;
import combi.wip.sipper.modeling.genomes.Genome;
import combi.wip.sipper.modeling.integratedModel.graphs.GraphGenomicModel;
import combi.wip.sipper.modeling.metabolicNetworks.MetabolicNetworkWithEnzymes;
import combi.wip.sipper.modeling.reactions.Reaction;



public class GenomicModel<G extends Gene<E>,C,R extends Reaction<C>, E extends Protein> extends IntegratedModel<G,C,R,E> {

	protected Catalyze<Gene<E>,Reaction<C>, C, E> catalyticUnits;

	public GenomicModel(MetabolicNetworkWithEnzymes<C, Reaction<C>, E> meta,
			Genome<Gene<E>,E> genome, 
			DistanceBetweenGenes<G> distance)
	{
		this.meta = meta;
		this.genome = genome;
		this.catalyticUnits = new Catalyze<Gene<E>,Reaction<C>,C, E>(this.genome, this.meta);
		this.distance = distance;
	}
	

	@Override
	public Collection<Gene<E>> getGeneSet() {
		return genome;
	}

	@Override
	public Collection<Protein> getEnzymeSet() {
		Collection<Protein>	result = new HashSet<Protein>(meta.getEnzymeSet());
		result.retainAll(genome.getProductSet());
		return result;
	}

	public Collection<Protein> getDeepProteinSet() {
		Collection<Protein>	result = new HashSet<Protein>();
		for (Protein p : meta.getEnzymeSet())
		{
			result.addAll(p.getDeepComponents());
		}
		result.retainAll(genome.getProductSet());
		return result;
	}

	@Override
	public Collection<Reaction<C>> getReactionSet() {
		// TODO Auto-generated method stub
		return meta.getReactionSet();
	}

	public DistanceBetweenGenes<G> getDistance()
	{
		return this.distance;	
	}

	public Collection<Gene<E>> getGenes(Reaction<C> r)
	{
		Collection<Gene<E>> genes = catalyticUnits.getReactionToGenes().get(r);
		if (genes ==null)
		{
			return new HashSet<Gene<E>>();
		}
		return genes;
	}

	public double getDistance(G src, G dest)
	{
		return distance.get(src, dest);
	}

	public double getDistanceMin(R src, R dest)
	{
		double result = Double.POSITIVE_INFINITY;
		for (Gene<E> gSrc : this.getGenes(src))
		{
			for (Gene<E> gDest : this.getGenes(src))
			{
				distance.get((G)gSrc, (G)gDest);
			}
		}
		return result;
	}

	@Override
	public void generateGraph() {
		this.graph = new GraphGenomicModel<G,C,R,E>(this);
		this.graph.generateGraph();
	}

	@Override
	public List<Gene<E>> getGenes(Collection<Integer> vertices) {
		List<Gene<E>> result = new ArrayList<Gene<E>>();
		for (int v : vertices)
		{
			result.add(genome.getGene(this.graph.getGLabel(v)));
		}
		return result;
	}

	@Override
	public List<Reaction<C>> getReactions(Collection<Integer> vertices) {
		List<Reaction<C>> result = new ArrayList<Reaction<C>>();
		for (int v : vertices)
		{
			result.add(meta.getReaction(this.graph.getRLabel(v)));
		}
		return result;
	}
}
